package synchronization;

class SharedData {
	
	private String data;
	
	public synchronized void writeData(String data) {
		while (this.data != null) {
			try {
				System.out.println("WRITE: Data buffer is full. Waiting...");
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
		System.out.println("WRITE: Data buffer is empty. Writing...");
		this.data = data;
		System.out.println("WRITE: Data buffer is full. Sending notification...");
		this.notify();
	}
	
	public synchronized String readData() {
		while (this.data == null) {
			try {
				System.out.println("READ: Data buffer is empty. Waithing...");
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}			
		}
		System.out.println("READ: Data buffer is full. Reading...");
		String dataToReturn = this.data;
		this.data = null;
		System.out.println("READ: Data buffer is empty. Sending notification...");
		this.notify();
		return dataToReturn;
	}
}

class User extends Thread {
	public int counter;
	protected SharedData data;
	public User(String name, SharedData data) {
		this.counter = 0;
		this.data = data;
		this.setName(name);
		this.setDaemon(true);
		this.start();
	}
}

class WriterThread extends User {

	public WriterThread(String name, SharedData data) {
		super(name, data);
	}

	/* (non-Javadoc)
	 * @see java.lang.Thread#run()
	 */
	@Override
	public void run() {
		while (true) {
			System.out.println(this.getName() + " is writing data...");
			this.data.writeData("Hail");
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

class ReaderThread extends User {

	public ReaderThread(String name, SharedData data) {
		super(name, data);
	}

	/* (non-Javadoc)
	 * @see java.lang.Thread#run()
	 */
	@Override
	public void run() {
		while (true) {
			System.out.println(this.getName() + " is reading data...");
			System.out.println(this.getName() + " [" + this.data.readData() + "]");
		}
	}
}

public class WaitAndNotifyDemo {
    public static void main(String[] args) throws InterruptedException{
    	SharedData myData = new SharedData();
    	System.out.println("MAIN: Starting first thread...");
    	new WriterThread("Pesho", myData);
    	
    	System.out.println("MAIN: Starting second thread...");
    	new ReaderThread("Ginka", myData);
    	
		System.out.println("MAIN: Waiting...");
		Thread.sleep(1000);
		System.out.println("MAIN: Exiting...");
    }
}
